package com.hh.service;
import com.hh.pojo.Total;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PreDestroy;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Service
@EnableScheduling
public class ClientService {
    Logger logger = LoggerFactory.getLogger(getClass());

    //与服务器通信的异步Channel
    private AsynchronousSocketChannel channel;
    private final ExecutorService executor = Executors.newFixedThreadPool(20);
//    private final String defaultAddress="192.168.1.200";
//    private String address = "192.168.1.200";//"192.168.0.103";//"localhost";
    //private String address = "192.168.2.21";
    private String address = "192.168.16.1";
    private String port = "6004";//6004~6008


    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;
    @Autowired
    private TotalService totalService;

    /***
     * socket连接
     * ***/
    public void connect() throws Exception {
        ByteBuffer buff = ByteBuffer.allocate(1024);
        ExecutorService pool = Executors.newFixedThreadPool(5);
        //以指定线程池来创建一一个AsynchronousChannelGroup
        AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(pool);
        //以channelGroup作为组管理器来创建AsynchronousSocketChannel
        channel = AsynchronousSocketChannel.open(channelGroup);
        channel.connect(new InetSocketAddress(address, Integer.parseInt(port))).get(3, TimeUnit.SECONDS);
        buff.clear();
        channel.read(buff, null, new CompletionHandler<Integer, Object>() {
            private int countNull;      //记录传递过来的数据是空的次数
            private long currentTime = System.currentTimeMillis();

            @Override
            public void completed(Integer result, Object attachment) {
                buff.flip();
                String content = StandardCharsets.UTF_8.decode(buff).toString().trim();
                maxCount(content);
                try {
                    logger.info("============="+content);//打印输出内容
                    Total total = new Total();
                    Date date = new Date();
                    //温湿度帧：Hwdhe0511t+24.5h12.4onononT
                    if(content.matches("Hwdhe0511t.{16}T")){
                        String temp = content.substring(10,15);//温度
                        String humidity = content.substring(16,20);//湿度
                        String fenshan1 = content.substring(20,22);//风扇1
                        String fenshan2 = content.substring(22,24);//风扇2
                        String moshi = content.substring(24,26);//模式自动
                        total.setTemperature(Double.valueOf(temp));
                        total.setHumidity(Double.valueOf(humidity));
                        total.setStartTime(date);
                        String type="温湿度传感器";
                        total.setSensorType(type);
                        //保存到数据库
                        totalService.SaveTotal(total);
                        //发送数据到前端页面
                        simpMessagingTemplate.convertAndSend("/topic/temp",temp);
                        simpMessagingTemplate.convertAndSend("/topic/typewendu",type);
                        simpMessagingTemplate.convertAndSend("/topic/hum",humidity);
                        simpMessagingTemplate.convertAndSend("/topic/date",date);
                        simpMessagingTemplate.convertAndSend("/topic/fenshan1",fenshan1);
                        simpMessagingTemplate.convertAndSend("/topic/fenshan2",fenshan2);
                        simpMessagingTemplate.convertAndSend("/topic/moshi",moshi);
                    } //光照度帧：Hwdie0312000000of00ofT
                    else if(content.matches("Hwdie0312.{12}T")){
                        String light = content.substring(9,15);
                        String lightType = content.substring(15,17);
                        String dianjiOn = content.substring(17,19);
                        String type1 = content.substring(19,21);
                        total.setLight(Double.valueOf(light));
                        total.setStartTime(date);
                        String type="光照度传感器";
                        total.setSensorType(type);
                        //保存到数据库
                        totalService.SaveTotal(total);
                        //发送数据到前端页面
                        simpMessagingTemplate.convertAndSend("/topic/typelight",type);
                        simpMessagingTemplate.convertAndSend("/topic/light",light);
                        simpMessagingTemplate.convertAndSend("/topic/lightType",lightType);
                        simpMessagingTemplate.convertAndSend("/topic/dianjiOn",dianjiOn);
                        simpMessagingTemplate.convertAndSend("/topic/type1",type1);
                    }//步进电机 停止帧：Hwddj050000T
                    else if(content.matches("Hwddj050000T")){
                        //发消息,直接将打开可调灯的帧数据发过去
                        String motor="Hwcdd0502onT";
                        simpMessagingTemplate.convertAndSend("/topic/motor",motor);
                    }// Hwdvl050400（上限）00(下限)T
                    else if(content.matches("Hwdvl0504.{4}T")){
                        //拿到温度上下限阈值
                        String upperTemp = content.substring(11,13);
                        String lowerTemp = content.substring(9,11);
                        simpMessagingTemplate.convertAndSend("/topic/lowerTemp",lowerTemp);
                        simpMessagingTemplate.convertAndSend("/topic/upperTemp",upperTemp);

                    }//Hwdlv0306000000T
                    else if(content.matches("Hwdlv0306.{6}T")){
                        //拿到光照上下限阈值
                        String upperLight= content.substring(9,15);
                        simpMessagingTemplate.convertAndSend("/topic/upperLight",upperLight);

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

                buff.clear();
                try {
                    channel.read(buff, null, this);
                } catch (NullPointerException n) {
                    logger.error(n.getMessage());
                }
            }
            //假设服务器掉线情况，就会发送无数垃圾数据过来，导致程序卡顿，这里检测发送过来的短时间内的次数，超过十次就让它断开连接
            private void maxCount(String content) {
                if ("".equals(content)) {
                    if (System.currentTimeMillis() - currentTime < 500) {
                        countNull++;
                    } else {
                        countNull = 0;
                    }
                    currentTime = System.currentTimeMillis();
                    if (countNull > 10) {
                        try {
                            disConnect();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        logger.error("超过十次没有收到空数据,就退出");
                    }
                }
            }

            @Override
            public void failed(Throwable exc, Object attachment) {
                System.out.println("控制台连接退出");
            }
        });
    }
    @Scheduled(fixedRate=10000)     //每间隔10秒执行一次, 检查是否掉线, 是就让它重新连接至服务器
    private void configureTasks() {
        if (channel == null || !channel.isOpen()){
            try {
                connect();
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
        }
    }

    /**
     * 关闭连接
     */
    public void disConnect() throws IOException {
        if (this.channel != null && channel.isOpen()) {
            channel.shutdownInput();
            channel.shutdownOutput();
            channel.close();
            channel = null;
        }
    }

    /**
     * 该对象销毁（Build）时，销毁与服务器连接
     */
    @PreDestroy
    public void detroyComponent() throws IOException {
        disConnect();
    }

    public AsynchronousSocketChannel getChannel() {
        return channel;
    }
}
